package nachos.threads;
import nachos.machine.*;


 // A communicator allows threads to exchange integers. Multiple threads
 // can be waiting to speak, and multiple threads can be waiting to listen. 
 
public class Communicator 
{
	public Communicator() 
	{
		lock = new Lock();
		isSpeaking = new Condition(lock);
		isListening = new Condition(lock);
		isEmpty = true;
	}


	//calling thread waits until it is paired with a listener
	//then it passes an integer to the listener
	public void speak(int message) 
	{
		this.lock.acquire();  //Get a lock... so that this transaction is atomic
	
		while(!isEmpty)  //While there is a word already present, this speaker should wait
		{
			this.isSpeaking.sleep();    //similar to wait on a semaphore
		}
		word = message;     //When word is empty, speaker can say the message
		isEmpty = false;    //Then word is not empty
		this.isListening.wakeAll();   //signals the listeners to wake
		this.lock.release();    //Release the lock, end transaction
	}

	//caller listens until another thread calls speak
	//it will then get an integer from the other thread
	//it returns the integer
	public int listen() 
	{
		this.lock.acquire();   //Get a lock... so that this transaction is atomic
		while(isEmpty)        //While there is no word, then this listener should wait
		{
			this.isListening.sleep();
		}
		isEmpty = true;   //Say that the word is empty
		int word = this.word;   //When a word appears, get it
    
		this.isSpeaking.wakeAll(); //wake up all threads sleeping in this condition
		this.lock.release();   //release the lock, end transaction
		return word;  
	}
  
  
	public Lock lock;   //Lock for mutual exclusion and condition variables
	public Condition isSpeaking;  //Both conditions share the lock
	public Condition isListening;
	public boolean isEmpty;   //This indicates if word is empty or not
	private int word;     //holds the message
}
